﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics.Contracts;
using System.Security;
using System.Runtime.InteropServices;

namespace EnumUtils
{
  public class FlagEnumToIEnumerableAdapter : IEnumerable, IComparable, IConvertible, IFormattable
  {
//TODO: Test me!
//TODO: Ask permission from Microsoft to use the documentation for System.Enum in your Enum wrapper wrapper class.
    public Enum WrappedEnum { get; private set; }
//TODO: Provide operators to automatically convert to and from regular enums.


    #region Constructors
    public FlagEnumToIEnumerableAdapter() { }

    public FlagEnumToIEnumerableAdapter( Enum enumToWrap ) {
      Contract.Requires<ArgumentNullException>(enumToWrap != default(Enum));
      Contract.Requires<ArgumentException>(FlagEnumUtilities.DoesEnumHaveFlagsAttribute(enumToWrap));

      WrappedEnum = enumToWrap;
    }
    #endregion



    #region System.Enum interface
    [SecuritySafeCritical]
    public override bool
    Equals( object obj ) {
      return this.WrappedEnum.Equals(obj);
    }


    [ComVisible(true)]
    public static string 
    Format( Type enumType, object value, string format ) {
      return Enum.Format(enumType, value, format);
    }

    public override int
    GetHashCode( ) {
      return this.WrappedEnum.GetHashCode();
    }

    [ComVisible(true)]
    public static string 
    GetName( Type enumType, object value ) {
      return Enum.GetName(enumType, value);
    }

    [ComVisible(true)]
    public static string[] 
    GetNames( Type enumType ) {
      return Enum.GetNames(enumType);
    }

    public TypeCode 
    GetTypeCode( ) {
      return this.WrappedEnum.GetTypeCode();
    }

    [SecuritySafeCritical]
    [ComVisible(true)]
    public static Type 
    GetUnderlyingType( Type enumType ) {
      return Enum.GetUnderlyingType(enumType);
    }

    [ComVisible(true)]
    public static Array 
    GetValues( Type enumType ) {
      return Enum.GetValues(enumType);
    }

    public bool 
    HasFlag( Enum flag ) {
      return this.WrappedEnum.HasFlag(flag);
    }

    [ComVisible(true)]
    public static bool 
    IsDefined( Type enumType, object value ) {
      return Enum.IsDefined(enumType, value);
    }

    [ComVisible(true)]
    public static object 
    Parse( Type enumType, string value ) {
      return Enum.Parse(enumType, value);
    }

    [ComVisible(true)]
    public static object
    Parse( Type enumType, string value, bool ignoreCase ) {
      return Enum.Parse(enumType, value, ignoreCase);
    }


    [SecuritySafeCritical]
    [ComVisible(true)]
    public static object
    ToObject( Type enumType, byte value ) {
      return Enum.ToObject(enumType, value);
    }

    [SecuritySafeCritical]
    [ComVisible(true)]
    public static object
    ToObject( Type enumType, int value ) {
      return Enum.ToObject(enumType, value);
    }

    [SecuritySafeCritical]
    [ComVisible(true)]
    public static object
    ToObject( Type enumType, long value ) {
      return Enum.ToObject(enumType, value);
    }

    [ComVisible(true)]
    public static object
    ToObject( Type enumType, object value ) {
      return Enum.ToObject(enumType, value);
    }

    [SecuritySafeCritical]
    [ComVisible(true)]
    public static object
    ToObject( Type enumType, sbyte value ) {
      return Enum.ToObject(enumType, value);
    }

    [SecuritySafeCritical]
    [ComVisible(true)]
    public static object
    ToObject( Type enumType, short value ) {
      return Enum.ToObject(enumType, value);
    }

    [SecuritySafeCritical]
    [ComVisible(true)]
    public static object
    ToObject( Type enumType, uint value ) {
      return Enum.ToObject(enumType, value);
    }

    [SecuritySafeCritical]
    [ComVisible(true)]
    public static object
    ToObject( Type enumType, ulong value ) {
      return Enum.ToObject(enumType, value);
    }

    [SecuritySafeCritical]
    [ComVisible(true)]
    public static object
    ToObject( Type enumType, ushort value ) {
      return Enum.ToObject(enumType, value);
    }

    public override string
    ToString( ) {
      return this.WrappedEnum.ToString();
    }

    [Obsolete("The provider argument is not used. Please use ToString().")]
    public string 
    ToString( string format, IFormatProvider provider ) {
      return this.WrappedEnum.ToString(format, provider);
    }

    [SecuritySafeCritical]
    public static bool 
    TryParse<TEnum>( string value, out TEnum result ) where TEnum : struct {
      return Enum.TryParse<TEnum>(value, out result);
    }

    [SecuritySafeCritical]
    public static bool 
    TryParse<TEnum>( string value, bool ignoreCase, out TEnum result ) where TEnum : struct {
      return Enum.TryParse<TEnum>(value, ignoreCase, out result);
    }
    #endregion


    #region IComparable Interface
    [SecuritySafeCritical]
    public int 
    CompareTo( object target ) {
      return this.WrappedEnum.CompareTo(target);
    }
    #endregion


    #region IFormattable Interface
    [Obsolete("The provider argument is not used. Please use ToString().")]
    public string
    ToString( IFormatProvider provider ) {
      return this.WrappedEnum.ToString(provider);
    }

    [SecuritySafeCritical]
    public string
    ToString( string format ) {
      return this.WrappedEnum.ToString(format);
    }
    #endregion



    #region IEnumerable Members
    public IEnumerator 
    GetEnumerator( ) {
      return FlagEnumUtilities.GetEnumerator(this.WrappedEnum);
    }
    #endregion

    #region IConvertible Members

    TypeCode IConvertible.GetTypeCode( ) {
      return (this.WrappedEnum as IConvertible).GetTypeCode();
    }

    bool IConvertible.ToBoolean( IFormatProvider provider ) {
      return (this.WrappedEnum as IConvertible).ToBoolean(provider);
    }

    byte IConvertible.ToByte( IFormatProvider provider ) {
      return (this.WrappedEnum as IConvertible).ToByte(provider);
      
    }

    char IConvertible.ToChar( IFormatProvider provider ) {
      return (this.WrappedEnum as IConvertible).ToChar(provider);
    }

    DateTime IConvertible.ToDateTime( IFormatProvider provider ) {
      return (this.WrappedEnum as IConvertible).ToDateTime(provider);
    }

    decimal IConvertible.ToDecimal( IFormatProvider provider ) {
      return (this.WrappedEnum as IConvertible).ToDecimal(provider);
    }

    double IConvertible.ToDouble( IFormatProvider provider ) {
      return (this.WrappedEnum as IConvertible).ToDouble(provider);
    }

    short IConvertible.ToInt16( IFormatProvider provider ) {
      return (this.WrappedEnum as IConvertible).ToInt16(provider);
    }

    int IConvertible.ToInt32( IFormatProvider provider ) {
      return (this.WrappedEnum as IConvertible).ToInt32(provider);
    }

    long IConvertible.ToInt64( IFormatProvider provider ) {
      return (this.WrappedEnum as IConvertible).ToInt64(provider);
    }

    sbyte IConvertible.ToSByte( IFormatProvider provider ) {
      return (this.WrappedEnum as IConvertible).ToSByte(provider);
    }

    float IConvertible.ToSingle( IFormatProvider provider ) {
      return (this.WrappedEnum as IConvertible).ToSingle(provider);
    }

    string IConvertible.ToString( IFormatProvider provider ) {
      return (this.WrappedEnum as IConvertible).ToString(provider);
    }

    object IConvertible.ToType( Type conversionType, IFormatProvider provider ) {
      return (this.WrappedEnum as IConvertible).ToType(conversionType, provider);
    }

    ushort IConvertible.ToUInt16( IFormatProvider provider ) {
      return (this.WrappedEnum as IConvertible).ToUInt16(provider);
    }

    uint IConvertible.ToUInt32( IFormatProvider provider ) {
      return (this.WrappedEnum as IConvertible).ToUInt32(provider);
    }

    ulong IConvertible.ToUInt64( IFormatProvider provider ) {
      return (this.WrappedEnum as IConvertible).ToUInt64(provider);
    }
    #endregion
  }
}
